<?php
/**
 * 七牛对象存储
 * Created by PhpStorm.
 * User: phperstar
 * Date: 2019/11/12
 * Time: 3:57 PM
 */
namespace Util\QiNiu;

use Mall\Framework\Core\ResultWrapper;
use Mall\Framework\Core\ErrorCode;


class Kodo
{
    /**
     * 七牛密钥
     * @var string $secret_id
     */
    private $accessKey;

    /**
     * 七牛密钥
     * @var string $secret_key
     */
    private $secretKey;

    /**
     * 接口主域名
     */
    private $rsHost = 'http://rs.qiniu.com';


    /**
     *上传策略，参数规格详见
     * 官网文档地址https://developer.qiniu.com/kodo/manual/1206/put-policy
     */
    private static $policyFields = [
        'scope',
        'isPrefixalScope', // 是否以前缀为文件名
        'deadline', // 上传凭证有效时间
        'insertOnly', // 新增模式上传
        'callbackUrl',
        'callbackBody',
        'callbackHost',
        'callbackBodyType',
        'callbackFetchKey',
        'returnUrl',
        'returnBody',
        'endUser',
        'saveKey',
        'insertOnly',
        'detectMime',
        'mimeLimit',
        'fsizeMin',
        'fsizeLimit', // 限制文件上传最大值 单位byte
        'persistentOps',
        'persistentNotifyUrl',
        'persistentPipeline',
        'deleteAfterDays',
        'fileType',
    ];


    public function __construct($accessKey='', $secretKey='')
    {
        $this->accessKey = $accessKey;
        $this->secretKey = $secretKey;
    }

    /**
     * 生成上传凭证
     * 官方文档地址:
     * @param string $bucket 空间名
     * @param string $key    key标识
     * @return ResultWrapper
     */
    public function uploadToken($bucket, $key, $expires = 3600)
    {
        // 构造上传策略
        $putPolicy = [
            'scope' => $bucket, // 资源名称
            'deadline' => time() + $expires,
            'insertOnly'=>1,
        ];

        if( !empty($key) ){
            $putPolicy['scope'] .= ':'.$key;
        }

        // 编码上传策略字符串
        $encodedPutPolicy = self::base64_urlSafeEncode(json_encode($putPolicy));

        // 计算签名
        $hmac = hash_hmac('sha1', $encodedPutPolicy, $this->secretKey, true);

        // 对签名结果进行编码
        $encodeSign = self::base64_urlSafeEncode($hmac);

        return ResultWrapper::success($this->accessKey.':'.$encodeSign.':'.$encodedPutPolicy);
    }


    /**
     * 对提供的数据进行urlsafe的base64编码。
     *
     * @param string $data 待编码的数据，一般为字符串
     *
     * @return string 编码后的字符串
     * @link http://developer.qiniu.com/docs/v6/api/overview/appendix.html#urlsafe-base64
     */
    public static function base64_urlSafeEncode($data)
    {
        $find = array('+', '/');
        $replace = array('-', '_');
        return str_replace($find, $replace, base64_encode($data));
    }
    /**
     * 对提供的urlsafe的base64编码的数据进行解码
     *
     * @param string $str 待解码的数据，一般为字符串
     *
     * @return string 解码后的字符串
     */
    public static function base64_urlSafeDecode($str)
    {
        $find = array('-', '_');
        $replace = array('+', '/');
        return base64_decode(str_replace($find, $replace, $str));
    }

    /**
     * 删除资源
     * 官网文档地址:https://developer.qiniu.com/kodo/api/1257/delete
     */
    public function delete($bucket, $key)
    {
        $entry = $bucket.':'.$key;
        $encodedEntryURI = self::base64_urlSafeEncode($entry);
        $url = $this->rsHost.'/delete/'.$encodedEntryURI;
        $authorization = 'QBox ' . $this->signRequest($url, '', 'application/x-www-form-urlencoded');

        $curl_option = [
            CURLOPT_HTTPHEADER => [
                'Content-Type:application/x-www-form-urlencoded',
                'Authorization:'.$authorization,
            ],
        ];

        $reponse = request($url, null, 30,  true,   $curl_option);

        if($reponse['httpcode'] != 200){
            return ResultWrapper::fail('请求外部系统接口报错'.$reponse['httpcode'], ErrorCode::$apiNotResult);
        }else{
            $reponseData = json_decode($reponse['content'], true);
            if( isset($reponseData['error']) ){
                return ResultWrapper::fail($reponseData['error'], ErrorCode::$apiNotResult);
            }
            return ResultWrapper::success('删除成功');
        }
    }

    /**
     * 生成管理凭证
     * 官网文档地址：https://developer.qiniu.com/kodo/manual/1201/access-token
     * @param $urlString
     * @param $body
     * @param null $contentType
     * @return string
     */
    public function signRequest($urlString, $body, $contentType = null)
    {
        $url = parse_url($urlString);
        $data = '';
        if (array_key_exists('path', $url)) {
            $data = $url['path'];
        }
        if (array_key_exists('query', $url)) {
            $data .= '?' . $url['query'];
        }
        $data .= "\n";
        if ($body !== null && $contentType === 'application/x-www-form-urlencoded') {
            $data .= $body;
        }

        $hmac = hash_hmac('sha1', $data, $this->secretKey, true);

        return $this->accessKey . ':' . self::base64_urlSafeEncode($hmac);
    }

}